package option

import (
	"runtime"
	"time"

	"gitee.com/hasika/common-server/codec"
	"gitee.com/hasika/common-server/conn/inet"
	"gitee.com/hasika/common-server/frame"
)

type ServiceOption struct {
	coder              codec.ICoder
	sessionOption      ISessionOption
	packetOption       IPacketOption
	serverOptions      []*RemoteOption
	connectionCallback *inet.BaseConnectionCallback
	sessionCallback    *inet.BaseSessionCallback
	taskGoroutineNum   int64
	routers            []*ProtoMessageRouter
	fallbackHandler    MessageHandler
	beforeStopCallback func()
	afterStopCallback  func()
	kcpOption          *KcpOption
	listenRetryOption  ListenRetryOption
}

type KcpOption struct {
	StreamMode     bool
	WriteDelay     bool
	AckNoDelay     bool
	NoDelayMode    int
	Interval       time.Duration
	ResendMode     int
	NoCrowdControl int
	SendWindowSize int
	RcvWindowSize  int
	Mtu            int
}

type ListenRetryOption struct {
	RetryTime     time.Duration
	RetryInterval time.Duration
}

func NewServiceOption() *ServiceOption {
	ret := &ServiceOption{
		connectionCallback: &inet.BaseConnectionCallback{},
		sessionCallback:    &inet.BaseSessionCallback{},
		taskGoroutineNum:   int64(runtime.NumCPU() * 4),
	}
	return ret
}

func (s *ServiceOption) SetCoder(coder codec.ICoder) *ServiceOption {
	s.coder = coder
	return s
}

func (s *ServiceOption) SetSessionOption(sessionOption ISessionOption) *ServiceOption {
	s.sessionOption = sessionOption
	return s
}

func (s *ServiceOption) SetPacketOption(packetOption IPacketOption) *ServiceOption {
	s.packetOption = packetOption
	return s
}

func (s *ServiceOption) AddRemoteOption(listenOption *RemoteOption) *ServiceOption {
	s.serverOptions = append(s.serverOptions, listenOption)
	return s
}
func (s *ServiceOption) AddConnectionCallback(call inet.ConnectionCallback) *ServiceOption {
	s.connectionCallback.AddCallback(call)
	return s
}
func (s *ServiceOption) AddSessionCallback(call inet.Callback) *ServiceOption {
	s.sessionCallback.AddCallback(call)
	return s
}

func (s *ServiceOption) GetCoder() codec.ICoder {
	return s.coder
}

func (s *ServiceOption) GetSessionOption() ISessionOption {
	return s.sessionOption
}

func (s *ServiceOption) GetPacketOption() IPacketOption {
	return s.packetOption
}

func (s *ServiceOption) GetListenOptions() []*RemoteOption {
	return s.serverOptions
}

func (s *ServiceOption) GetConnectionCallback() inet.ConnectionCallback {
	return s.connectionCallback
}

func (s *ServiceOption) GetSessionCallback() inet.Callback {
	return s.sessionCallback
}

func (s *ServiceOption) GetConnectionToReaderWriter() map[inet.ConnectionType]frame.IFrameReaderWriter {
	ret := make(map[inet.ConnectionType]frame.IFrameReaderWriter)
	for _, option := range s.serverOptions {
		ret[option.network] = option.GetFrameReader()
	}
	return ret
}

func (s *ServiceOption) GetTaskGoroutineNum() int64 {
	return s.taskGoroutineNum
}

func (s *ServiceOption) SetTaskGoroutineNum(taskGoroutineNum int64) {
	s.taskGoroutineNum = taskGoroutineNum
}

func (s *ServiceOption) AddRouter(rt *ProtoMessageRouter) *ServiceOption {
	s.routers = append(s.routers, rt)
	return s
}

func (s *ServiceOption) Routers() []*ProtoMessageRouter {
	return s.routers
}

func (s *ServiceOption) SetFallbackHandler(fallback MessageHandler) *ServiceOption {
	s.fallbackHandler = fallback
	return s
}

func (s *ServiceOption) GetFallbackHandler() MessageHandler {
	return s.fallbackHandler
}

func (s *ServiceOption) BeforeStopCallback() func() {
	return s.beforeStopCallback
}

func (s *ServiceOption) SetBeforeStopCallback(beforeStopCallback func()) *ServiceOption {
	s.beforeStopCallback = beforeStopCallback
	return s
}

func (s *ServiceOption) PostStopCallback() func() {
	return s.afterStopCallback
}

func (s *ServiceOption) SetAfterStopCallback(postStopCallback func()) *ServiceOption {
	s.afterStopCallback = postStopCallback
	return s
}

func (s *ServiceOption) SetKcpOption(kcpOption *KcpOption) *ServiceOption {
	s.kcpOption = kcpOption
	return s
}

func (s *ServiceOption) KcpOption() *KcpOption {
	return s.kcpOption
}

func (s *ServiceOption) ListenRetryOption() ListenRetryOption {
	return s.listenRetryOption
}

func (s *ServiceOption) SetListenRetryOption(listenRetryOption ListenRetryOption) *ServiceOption {
	s.listenRetryOption = listenRetryOption
	return s
}
